home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / stdlib1.exe / lha / PRINTF.ASM < prev    next >
Assembly Source File  |  1990-06-23  |  15KB  |  707 lines

  1. stdlib        segment    para public 'slcode'
  2.         assume    cs:stdlib
  3.         extrn    sl_Putc:far, sl_Puti:far, sl_ISize:far
  4.         extrn    sl_Putw:far, sl_Puth:far
  5.         extrn    sl_Putu:far, sl_PutUL:far, sl_ULSize:far
  6.         extrn    sl_LSize:far, sl_USize:far, sl_PutL:far
  7. ;
  8. putc        equ    sl_putc
  9. puti        equ    sl_puti
  10. ISize        equ    sl_ISize
  11. putw        equ    sl_putw
  12. puth        equ    sl_puth
  13. putu        equ    sl_putu
  14. putul        equ    sl_putul
  15. ulsize        equ    sl_ulsize
  16. lsize        equ    sl_lsize
  17. usize        equ    sl_usize
  18. putl        equ    sl_putl
  19. ;
  20. ;
  21. ; Printf- Like the "C" routine by the same name.  Calling sequence:
  22. ;
  23. ;               call    printf
  24. ;               db      "format string",0
  25. ;               dd      item1, item2, ..., itemn
  26. ;
  27. ; The format string is identical to "C".  Item1..Itemn are pointers to
  28. ; values to print for this string.  Each item must be matched by the
  29. ; corresponding "%xxx" item in the format string.
  30. ;
  31. ; Format string format:
  32. ;
  33. ; 1)    All characters, except the following, are printed to the standard
  34. ;       output as-is.
  35. ;
  36. ; 2)    "\" is the escape character.  Anything following it is printed
  37. ;       as-is except standard "C" values like \r, \n, \b, \t, etc.  If
  38. ;       a decimal digit follows the back-slash, printf assumes that this
  39. ;       is a hexadecimal number and converts following three digits to
  40. ;       an ASCII character and prints it.  Other back-slash operators are
  41. ;       just like those for "C".
  42. ;
  43. ; 3)    Format Control Strings:
  44. ;
  45. ;    General format:  "%s\cn^f" where:
  46. ;                s = -
  47. ;                n = a decimal integer
  48. ;                c = a fill character
  49. ;                ^ = ^
  50. ;                f = a format character
  51. ;
  52. ;            All fields except "%" and "f" are optional.
  53. ;
  54. ;    s = -       Left justify value and use fill character.
  55. ;    \c present    Use "c" as fill character.
  56. ;    n present    Use "n" as the minimum field width.
  57. ;    ^ present    The address associated with f is the address of a
  58. ;                pointer to the object, not the address of
  59. ;                the object itself.  The pointer is a far ptr.
  60. ;
  61. ;    f is one of the following
  62. ;
  63. ;        d -    Print signed integer in decimal notation.
  64. ;        i -    Print signed integer in decimal notation.
  65. ;        x -    Print word value in hexadecimal notation.
  66. ;        h -    Print byte value in hexadecimal notation.
  67. ;        u -    Print unsigned integer in decimal notation.
  68. ;        c -    Print character.
  69. ;        s -    Print string.
  70. ;
  71. ;        ld-    Print long signed integer.
  72. ;        li-    Print long unsigned integer.
  73. ;        lx-    Print long hexadecimal number.
  74. ;        lu-    Print long unsigned number.
  75. ;
  76. ;
  77. ;    Calling Sequence:
  78. ;
  79. ;        call    Printf
  80. ;        db    "Format String",0
  81. ;        dd    adrs1, adrs2, ..., adrsn
  82. ;
  83. ;    Where the format string is ala "C" (and the descriptions above)
  84. ;    and adrs1..adrsn are addresses (far ptr) to the items to print.
  85. ;    Unless the "^" modifier is present, these addresses are the actual
  86. ;    addresses of the objects to print.
  87. ;
  88. ;
  89. ;
  90. cr        equ    0dh
  91. ff        equ    0ch
  92. lf        equ    0ah
  93. tab        equ    09h
  94. bs        equ    08h
  95. ;
  96. RtnAdrs        equ    2[bp]
  97. ;
  98.         public  sl_printf
  99. sl_printf    proc    far
  100.         push    bp
  101.         mov    bp, sp
  102.         pushf
  103.         push    ax
  104.         push    bx
  105.         push    cx
  106.         push    dx
  107.         push    di
  108.         push    si
  109.         push    es
  110.         push    ds
  111. ;
  112. ; Get pointers to the return address (format string).
  113.         cld
  114.         les    di, RtnAdrs
  115.         lds    si, RtnAdrs
  116. ;
  117. ; Okay, search for the end of the format string.  After these instructions,
  118. ; di points just beyond the zero byte at the end of the format string.  This,
  119. ; of course, points at the first address beyond the format string.
  120. ;
  121.         mov    al, 0
  122.         mov    cx, 65535
  123.     repne    scasb
  124. ;
  125. PrintItems:    lodsb            ;Get char si points at.
  126.         cmp    al, 0        ;EOS?
  127.         jz    PrintfDone
  128.         cmp    al, "%"        ;Start of a format string?
  129.         jz    FmtItem
  130.         cmp    al, "\"        ;Escape character?
  131.         jnz    PrintIt
  132.         call    GetEscChar
  133. PrintIt:    call    Putc
  134.         jmp    PrintItems
  135. ;
  136. FmtItem:    call    GetFmtItem    ;Process the format item here.
  137.         jmp    PrintItems
  138. ;
  139. PrintfDone:    mov    RtnAdrs, di    ;Put out new return address.
  140.         pop    ds
  141.         pop    es
  142.         pop    si
  143.         pop    di
  144.         pop    dx
  145.         pop    cx
  146.         pop    bx
  147.         pop    ax
  148.         pop    bp
  149.         popf
  150.         ret
  151. sl_printf       endp
  152. ;
  153. ; GetEscChar- Handles items immediately following the escape character "\".
  154. ;
  155. ;    Special escape characters (upper/lower case is acceptable):
  156. ;
  157. ;        n    Newline (cr/lf)
  158. ;        t    tab
  159. ;        b    backspace
  160. ;        r    return
  161. ;        l    line feed
  162. ;        f    formfeed
  163. ;        \    \
  164. ;        %    &
  165. ;        0xhh    Char with hex character code hh.  Must have exactly
  166. ;            two hexadecimal digits.
  167. ;
  168. GetEscChar    proc    near
  169.         lodsb            ;Get next character
  170.         cmp    al, 'n'
  171.         je    RtnNL
  172.         cmp    al, 'N'
  173.         je    RtnNL
  174.         cmp    al, 't'
  175.         je    RtnTab
  176.         cmp    al, 'T'
  177.         je    RtnTab
  178.         cmp    al, 'b'
  179.         je    RtnBS
  180.         cmp    al, 'B'
  181.         je    RtnBS
  182.         cmp    al, 'r'
  183.         je    RtnRtn
  184.         cmp    al, 'R'
  185.         je    RtnRtn
  186.         cmp    al, 'l'
  187.         je    RtnLF
  188.         cmp    al, 'L'
  189.         je    RtnLF
  190.         cmp    al, 'f'
  191.         je    RtnFF
  192.         cmp    al, 'F'
  193.         je    RtnFF
  194. ;
  195. ; Check for the presence of a 0xhh value here:
  196. ;
  197.         cmp    al, '0'
  198.         jne    RtnChar
  199.         cmp    byte ptr [si], 'x'
  200.         je    GetHex
  201.         cmp    byte ptr [si], 'X'
  202.         jne    RtnChar
  203. ;
  204. ; Okay, process the hex value here.  Note that exactly two hex digits must
  205. ; follow the 0x.
  206. ;
  207. GetHex:        inc    si        ;Point at first hex digit.
  208.         lodsb            ;Get first hex digit.
  209.         and    al, 05fh    ;l.c. -> u.c.
  210.         cmp    al, 'A'
  211.         jb    GotIt
  212.         sub    al, '7'
  213. GotIt:        shl    al, 1        ;Put into H.O. nibble.
  214.         shl    al, 1
  215.         shl    al, 1
  216.         shl    al, 1
  217.         mov    ah, al        ;Save for later
  218.         lodsb            ;Get next char.
  219.         and    al, 05fh
  220.         cmp    al, 'A'
  221.         jb    GotIt2
  222.         sub    al, '7'
  223. GotIt2:        and    al, 0fh
  224.         or    al, ah
  225.         ret            ;Return hex constant.
  226. ;
  227. ; RtnNL (return Newline) cheats.  It needs to return two characters.
  228. ; Since GetEscChar only returns a single character, this code goes ahead
  229. ; and calls putc to output the CR and the returns the LF.
  230. ;
  231. RtnNL:        mov    al, cr
  232.         call    Putc
  233.         mov    al, lf
  234.         ret
  235. ;
  236. RtnTab:        mov    al, tab
  237.         ret
  238. ;
  239. RtnBS:        mov    al, bs
  240.         ret
  241. ;
  242. RtnRtn:        mov    al, cr
  243.         ret
  244. ;
  245. RtnLF:        mov    al, lf
  246.         ret
  247. ;
  248. RtnFF:        mov    al, ff
  249. RtnChar:    ret
  250. ;
  251. GetEscChar    endp
  252. ;
  253. ;
  254. ;
  255. GetFmtItem    proc    near
  256.         lodsb                ;Get char beyond "%"
  257. ;
  258.         mov    cx, 1            ;Default field width is 1.
  259.         mov    dl, 0            ;Default is right justified
  260.         mov    dh, ' '            ;Default fill char is space.
  261.         mov    ah, ' '            ;Assume straight ptr, not handle.
  262. ;
  263. ; See if the user wants the value left justified:
  264. ;
  265.         cmp    al, '-'
  266.         jne    NotLeftJust
  267.         inc    dl            ;Set to right justified
  268.         lodsb                ;Get next character.
  269. ;
  270. ; See if the user wants to change the padding character.
  271. ;
  272. NotLeftJust:    cmp    al, '\'
  273.         jne    NoPadChange
  274.         lodsb                ;Get Padding Character.
  275.         mov    dh, al            ;Save padding character.
  276.         lodsb                ;Get next character
  277. ;
  278. ; See if the user wants a different field width:
  279. ;
  280. NoPadChange:    cmp    al, '0'
  281.         jb    NoFldWidth
  282.         cmp    al, '9'
  283.         ja    NoFldWidth
  284.         call    GetDecVal
  285. ;
  286. ; See if the user wants to specify a handle rather than a straight pointer
  287. ;
  288. NoFldWidth:    cmp    al, '^'
  289.         jne     ChkFmtChars
  290.         mov    ah, al
  291.         lodsb                ;Skip "^" character
  292. ;
  293. ; Okay, process the format characters down here.
  294. ;
  295. ChkFmtChars:    and    al, 05fh        ;l.c. -> U.C.
  296.         cmp    al, 'D'
  297.         je    PrintDec
  298.         cmp    al, 'I'
  299.         je    PrintDec
  300.         cmp    al, 'C'
  301.         je    PrintChar
  302. ;
  303.         cmp    al, 'X'
  304.         jne    TryH
  305.         jmp    PrintHexWord
  306. ;
  307. TryH:        cmp    al, 'H'
  308.         jne    TryU
  309.         jmp    PrintHexByte
  310. ;
  311. TryU:        cmp    al, 'U'
  312.         jne    TryString
  313.         jmp    PrintUDec
  314. ;
  315. TryString:    cmp    al, 'S'
  316.         jne    TryLong
  317.         jmp    PrintString
  318. ;
  319. TryLong:        cmp    al, 'L'
  320.         jne    Default
  321. ;
  322. ; If we've got the "L" modifier, this is a long value to print, get the
  323. ; data type character as the next value:
  324. ;
  325.         lodsb
  326.         and    al, 05fh        ;l.c. -> U.C.
  327.         cmp    al, 'D'
  328.         je    JmpDec
  329.         cmp    al, 'I'
  330.         jne    TryLU
  331. JmpDec:        jmp    LongDec
  332. ;
  333. TryLU:        cmp    al, 'U'
  334.         jne    TryX
  335.         jmp    LongU
  336. ;
  337. TryX:        cmp    al, 'X'
  338.         jne    Default
  339.         jmp    LongX
  340. ;
  341. ;
  342. ;
  343. ; If none of the above, simply return without printing anything.
  344. ;
  345. Default:        ret
  346. ;
  347. ;
  348. ;
  349. ;
  350. ;
  351. ; Print a signed decimal value here.
  352. ;
  353. PrintDec:    call    GetPtr            ;Get next pointer into ES:BX
  354.         mov    ax, es:[bx]        ;Get value to print.
  355.         call    ISize            ;Get the size of this guy.
  356.         sub    cx, ax                 ;Compute padding
  357.         mov    ax, es:[bx]        ;Retrieve value to print.
  358.         js    NoPadDec        ;Is CX negative?
  359.         cmp    dl, 0            ;Right justified?
  360.         jne    LeftJustDec
  361.         call    PrintPad        ;Print padding characters
  362.         call    Puti            ;Print the integer
  363.         ret                ;We're done!
  364. ;
  365. ; Print left justified value here.
  366. ;
  367. LeftJustDec:    call    Puti
  368.         call    PrintPad
  369.         ret
  370. ;
  371. ; Print non-justi